gusucode.com > VC 达内MFC例子集源码-源码程序 > VC 达内MFC例子集源码-源码程序/code/20101228/day02.txt
一 消息映射 1 消息映射添加 1.1 在FrameWnd添加消息宏定义 DECLARE_MESSAGE_MAP 1.2 添加消息宏实现 BEGIN_MESSAGE_MAP( theClass, parentClass ) END_MESSAGE_MAP( ) 1.3 添加消息处理函数 afx_msg LRESULT OnPaint( WPARAM wParam, LPARAM lParam ); 1.4 添加消息和处理函数的对应 ON_MESSAGE( WM_PAINT, OnPaint ) 2 消息宏的实现 2.1 数据类型 2.1.1 AFX_MSGMAP_ENTRY 是用于保存 消息ID与对应函数指针,及相关的信息 struct AFX_MSGMAP_ENTRY { UINT nMessage; //消息ID UINT nCode;//通知代码 UINT nID; //控件的ID UINT nLastID;//控件的ID范围的最后 UINT nSig;//操作类型或pfn函数类型 AFX_PMSG pfn;//消息处理函数的函数指针 }; 2.1.2 AFX_MSGMAP 用于保存GetBaseMap 的函数地址及AFX_MSGMAP_ENTRY数组的 地址. struct AFX_MSGMAP { const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)(); //函数指针 const AFX_MSGMAP_ENTRY* lpEntries; //AFX_MSGMAP_ENTRY类型指针 }; 2.2 宏代码 class CMsgFrame : public CFrameWnd { private: //保存消息ID和对应的处理函数的数组 static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: //保存了CMsgFrame中的_GetBaseMessageMap //函数指针以及_messageEntries数组地址 static AFX_DATA const AFX_MSGMAP messageMap; static const AFX_MSGMAP* PASCAL _GetBaseMessageMap(); virtual const AFX_MSGMAP* GetMessageMap() const; } const AFX_MSGMAP* PASCAL CMsgFrame::_GetBaseMessageMap() { return &CFrameWnd::messageMap; } const AFX_MSGMAP* CMsgFrame::GetMessageMap() const { return &CMsgFrame::messageMap; } AFX_COMDAT AFX_DATADEF const AFX_MSGMAP CMsgFrame::messageMap = { &CMsgFrame::_GetBaseMessageMap, &CMsgFrame::_messageEntries[0] }; AFX_COMDAT const AFX_MSGMAP_ENTRY CMsgFrame::_messageEntries[] = { { WM_PAINT, 0, 0, 0, AfxSig_lwl,(AFX_PMSG)(AFX_PMSGW)(LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM))&OnPaint }, {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } }; 2.3 代码说明 2.3.1 _messageEntries[], 静态 类型为 AFX_MSGMAP_ENTRY 保存CMsgFrame中消息ID和对应的 消息处理函数的数组 2.3.2 messageMap, 静态 类型为 AFX_MSGMAP 保存了CMsgFrame中的_GetBaseMessageMap 函数指针以及_messageEntries数组地址 2.3.3 _GetBaseMessageMap, 静态 获取父类的messageMap的地址 2.3.4 GetMessageMap,虚函数 获取自己的messageMap地址 2.4 代码关系 CMsgFrame::GetMessageMap -〉&messageMap{ &_messageEntries[0] -> { ID<->Func, ID<->Func, .... } _GetBaseMessageMap -> &parent::messageMap { &_messageEntries[0], _GetBaseMessageMap->&parent::messageMap } } 3 消息映射过程 3.1 消息处理函数WindowProc收到消息后, 调用OnWndMsg处理消息,OnWndMsg如果不 处理消息,那么WindowProc将调用 DefWindowProc默认处理消息并返回. 3.2 OnWndMsg处理消息 3.2.1 使用GetMessageMap函数获取该 窗口类的messageMap变量的地址. const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap(); 3.2.2 在messageMap中的lpEntries数组 中,查找消息ID所对应的数组元素. 3.2.3 如果未找到,获取父类的messageMap 指针,返回3.2.2,从父类的lpEntries 数组继续查找. 3.2.4 如果找到,获取找到的数组元素的 地址lpEntry,退出查找过程,执行下一步. const AFX_MSGMAP_ENTRY* lpEntry = NULL; for ( ; pMessageMap != NULL; pMessageMap = (*pMessageMap->pfnGetBaseMap)()) { lpEntry = AfxFindMessageEntry( pMessageMap->lpEntries, message, 0, 0)) if( lpEntry != NULL ) { goto LDispatch; } } 3.2.5 根据找到的lpEntry的nSig标识, 调用lpEntry当中的pfn函数指针,处理 消息. LDispatch: union MessageMapFunctions mmf; mmf.pfn = lpEntry->pfn; int nSig; nSig = lpEntry->nSig; switch (nSig) { case AfxSig_lwl: lResult = (this->*mmf.pfn_lwl)(wParam, lParam); break; } 二 MFC的消息分类 1 窗口消息 例如WM_CREATE、WM_PAINT、鼠标、键盘等 消息,这些消息的处理方式是直接调用消息 处理函数. 这类消息使用的宏: ON_MESSAGE( ) ON_WM_XXXXX( ): ON_WM_CREATE() 消息处理时,采用3.2的处理方式. 2 命令消息 WM_COMMAND 菜单、工具栏、按钮等点击时的命令. 消息 首先发送到主窗口,由主窗口逐层向子窗口 派发。 这类的消息使用的宏: ON_COMMAND( ) ON_COMMAND_RANGE( ) 消息处理时,在OnWndMsg中调用OnCommand 处理函数进行消息处理. 3 通知消息 WM_NOTIFY 子窗口对父窗口的通知消息。 控件消息宏, 例如: EDIT控件 ON_EN_CHANGE ON_NOTIFY/ON_NOTIFY_RANGE 消息处理时,在OnWndMsg中调用OnNotify (OnCommand)处理函数进行消息处理 4 自注册消息 用户自注册消息的处理。用户需调用 RegisterWindowMessage函数注册消息,然后 在消息映射中使用. UINT RegisterWindowMessage( LPCTSTR lpString //消息名字符串 ); 返回注册成功的消息ID(0xC000-0xFFFF) 消息映射宏: ON_REGISTERED_MESSAGE 消息处理时, 与窗口消息处理类似,但是 在查找消息处理函数和执行消息处理函数 时不同. 三 MFC菜单 1 MFC菜单相关类 CMenu类 - 封装HMENU句柄,及相关的菜单的 API函数. 2 菜单的用法 2.1 菜单资源的添加 2.2 创建时,在窗口中添加菜单 2.3 菜单项的命令相应ON_COMMAND 3 注意: 只有是继承CCmdTarget的子类,都可以添加 消息映射机制.